{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# hex adapter demo\n",
    "\n",
    "*<<< check out other demo models [here](https://github.com/FullControlXYZ/fullcontrol/tree/master/models/README.md) >>>*\n",
    "  \n",
    "press ctrl+F9 to run all cells in this notebook, or press shift+enter to run each cell sequentially \n",
    "\n",
    "if you change one of the code cells, make sure you run it and all subsequent cells again (in order)\n",
    "\n",
    "*this document is a jupyter notebook - if they're new to you, check out how they work: [link](https://www.google.com/search?q=ipynb+tutorial), [link](https://jupyter.org/try-jupyter/retro/notebooks/?path=notebooks/Intro.ipynb), [link](https://colab.research.google.com/)*\n### be patient :)\n\nthe next code cell may take a while because running it causes several things to happen:\n- connect to a google colab server -> download the fullcontrol code -> install the fullcontrol code\n\ncheck out [other tutorials](https://github.com/FullControlXYZ/fullcontrol/blob/master/tutorials/README.md) to understand the python code for the FullControl design"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if 'google.colab' in str(get_ipython()):\n  !pip install git+https://github.com/FullControlXYZ/fullcontrol --quiet\nimport fullcontrol as fc\nfrom google.colab import files\n",
    "from math import tau\n",
    "from copy import deepcopy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# printer/gcode parameters\n",
    "\n",
    "design_name = 'hex_adapter'\n",
    "nozzle_temp = 210\n",
    "bed_temp = 40\n",
    "print_speed = 1000\n",
    "fan_percent = 100\n",
    "printer_name='prusa_i3' # generic / ultimaker2plus / prusa_i3 / ender_3 / cr_10 / bambulab_x1 / toolchanger_T0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# design parameters\n",
    "\n",
    "inner_size = 10\n",
    "# Inner Hex (mm) - Size of hexagonal hole (space between two opposing inner hexagon walls)\n",
    "# default value: 10 \n",
    "\n",
    "outer_size = 16\n",
    "# Outer Hex (mm) - Size of outer hexagonal shape (distance between outer edges of two opposing outer hexagon walls)\n",
    "# default value: 16 \n",
    "\n",
    "height = 4\n",
    "# Thickness (mm) - Thickness of the adapter\n",
    "# default value: 4\n",
    "\n",
    "inner_oversize = 0.2\n",
    "# Inner Hex Oversize (mm) - This can be used to finely adjust the size of the inner hexagon (positive value makes hole bigger)\n",
    "# default value: 0.2\n",
    "\n",
    "outer_undersize = 0.2\n",
    "# Outer Hex Undersize (mm) - This can be used to finely adjust the size of the outer hexagon (positive value makes part smaller)\n",
    "# default value: 0.2\n",
    "\n",
    "EW = 0.6\n",
    "# Extrusion Width (mm) - Width of printed lines - recommended value: 1.5x nozzle diameter\n",
    "# default value: 0.6\n",
    "\n",
    "EH = 0.2\n",
    "# Extrusion Height (mm) - Height of printed lines (i.e. layer thickness) - recommended value: 0.5x nozzle diameter\n",
    "# default value: 0.2\n",
    "\n",
    "quantity = 1\n",
    "# Quantity - Number of parts to print\n",
    "# default value: 1 ; guideline range: 1 to 5\n",
    "\n",
    "multipart_offset_x = 0\n",
    "# Multipart Offset X (mm) - Space between parts in X direction when quantity > 1\n",
    "# default value: 0 \n",
    "\n",
    "multipart_offset_y = 40\n",
    "# Multipart Offset Y (mm) - Space between parts in Y direction when quantity > 1\n",
    "# default value: 40\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# generate the design (make sure you've run the above cells before running this cell)\n",
    "\n",
    "\n",
    "layers = int(height/EH)\n",
    "inner_size += EW/2 \n",
    "outer_size -= EW/2 \n",
    "\n",
    "r_hex_inner = (inner_size/2)*(2/(3**0.5)) + inner_oversize\n",
    "r_hex_outer = (outer_size/2)*(2/(3**0.5)) - outer_undersize\n",
    "\n",
    "centre = fc.Point(x=0,y=0,z=0)\n",
    "\n",
    "hex_outer = fc.polygonXY(centre, r_hex_outer, tau/2, 6, cw=False)\n",
    "hex_inner = fc.polygonXY(centre, r_hex_inner, tau/2, 6, cw=False)\n",
    "\n",
    "hex_unit = []\n",
    "hex_unit.append(hex_outer[0])\n",
    "hex_unit.append(fc.midpoint(hex_outer[0],hex_outer[5]))\n",
    "hex_unit.append(hex_inner[0])\n",
    "hex_unit.append(hex_inner[1])\n",
    "hex_unit.append(fc.midpoint(hex_outer[1],hex_outer[2]))\n",
    "hex_unit.append(hex_outer[1])\n",
    "\n",
    "steps_one_layer = []\n",
    "for i in range(6):\n",
    "  rotation=i*(tau/6)\n",
    "  steps_one_layer += fc.move_polar(hex_unit,centre,0,rotation)\n",
    "  \n",
    "steps_multilayer = fc.move(steps_one_layer, fc.Vector(z=EH), True, layers)\n",
    "\n",
    "if quantity > 1:\n",
    "    # need deepcopy since we refer to steplist_multilayer in every loop and don't want to modify it\n",
    "    steps_array = deepcopy(steps_multilayer)\n",
    "    prime_radius = r_hex_outer+5*EW\n",
    "    for i in range(quantity-1):\n",
    "        centre_now = fc.Point(x=centre.x+multipart_offset_x*(i+1), y=centre.y+multipart_offset_y*(i+1))\n",
    "        # move to new start point without extrusion\n",
    "        steps_array.append(fc.Extruder(on=False))\n",
    "        steps_array.append(fc.Point(z=height+1))\n",
    "        # begin outside the primer circle to keep polymer drool away from the part\n",
    "        steps_array.append(fc.Point(x=centre_now.x-prime_radius-5, y=centre_now.y))\n",
    "        steps_array.append(fc.Point(z=0))\n",
    "        # print a circle to get flow going\n",
    "        steps_array.append(fc.Extruder(on=True))\n",
    "        steps_array.extend(fc.circleXY(centre_now,prime_radius,tau/2,32))\n",
    "        steps_array.extend(fc.move(steps_multilayer, fc.Vector(x=multipart_offset_x*(i+1),y=multipart_offset_y*(i+1))))\n",
    "    steps_multilayer = steps_array\n",
    "\n",
    "# offset the whole procedure. z dictates the gap between the nozzle and the bed for the first layer, assuming the model was designed with a first layer z-position of 0\n",
    "model_offset = fc.Vector(x=30, y=30, z=0.8*EH)\n",
    "steps = fc.move(steps_multilayer, model_offset)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# preview the design\n",
    "\n",
    "# fc.transform(steps, 'plot', fc.PlotControls(style='line'))\n",
    "# hover the cursor over the lines in the plot to check xyz positions of the points in the design\n",
    "\n",
    "# uncomment the next line to create a plot with real heights/widths for extruded lines to preview the real 3D printed geometry\n",
    "fc.transform(steps, 'plot', fc.PlotControls(zoom=0.7, style='tube', initialization_data={'extrusion_width': EW, 'extrusion_height': EH}))\n",
    "\n",
    "# uncomment the next line to create a neat preview (click the top-left button in the plot for a .png file) - post and tag @FullControlXYZ :)\n",
    "# fc.transform(steps, 'plot', fc.PlotControls(neat_for_publishing=True, zoom=0.7,  initialization_data={'extrusion_width': EW, 'extrusion_height': EH}))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# generate and save gcode\n",
    "\n",
    "gcode_controls = fc.GcodeControls(\n",
    "    printer_name=printer_name,\n",
    "\n",
    "    initialization_data={\n",
    "        'primer': 'front_lines_then_y',\n",
    "        'print_speed': print_speed,\n",
    "        'nozzle_temp': nozzle_temp,\n",
    "        'bed_temp': bed_temp,\n",
    "        'fan_percent': fan_percent,\n",
    "        'extrusion_width': EW,\n",
    "        'extrusion_height': EH})\n",
    "gcode = fc.transform(steps, 'gcode', gcode_controls)\nopen(f'{design_name}.gcode', 'w').write(gcode)\nfiles.download(f'{design_name}.gcode')"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### please tell us what you're doing with FullControl!\n",
    "\n",
    "- tag FullControlXYZ on social media ([twitter](https://twitter.com/FullControlXYZ), [instagram](https://www.instagram.com/fullcontrolxyz/), [linkedin](https://www.linkedin.com/in/andrew-gleadall-068587119/), [tiktok](https://www.tiktok.com/@fullcontrolxyz))\n",
    "- email [info@fullcontrol.xyz](mailto:info@fullcontrol.xyz)\n",
    "- post on the [subreddit](https://reddit.com/r/fullcontrol)\n",
    "- post in the [github discussions or issues tabs](https://github.com/FullControlXYZ/fullcontrol/issues)\n",
    "\n",
    "in publications, please cite the original FullControl paper and the github repo for the new python version:\n",
    "\n",
    "- Gleadall, A. (2021). FullControl GCode Designer: open-source software for unconstrained design in additive manufacturing. Additive Manufacturing, 46, 102109. \n",
    "- Gleadall, A. and Leas, D. (2023). FullControl [electronic resource: python source code]. available at: https://github.com/FullControlXYZ/fullcontrol"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.3"
  },
  "vscode": {
   "interpreter": {
    "hash": "2b13a99eb0d91dd901c683fa32c6210ac0c6779bab056ce7c570b3b366dfe237"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
